package com.danicsoft.daide.historian;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;

import com.danicsoft.daide.command.Turn;
import com.danicsoft.daide.serverclient.Server;
import com.danicsoft.daide.serverclient.TurnInfo;

/**
 * Handles all logging for a server. It implements functionality for tracking
 * various client's information as well.
 * 
 * @author Daniel Yule (daniel.yule@gmail.com)
 * @version 1.0
 */
public class ServerHistorian extends CommandHistorian {

	/**
	 * A reference to the earliest turn logged. If an earlier turn is logged,
	 * then that turn replaces it.
	 */
	private TurnInfo firstTurn;

	/**
	 * A mapping of turns to turn infos. This stores all turns information based
	 * on the turn that came before. This allows for easy iteration and
	 * implementation of the HST command.
	 */
	private Map<Turn, TurnInfo> turns = new HashMap<Turn, TurnInfo>();

	/**
	 * Construct a new ServerHistorian using a default console output.
	 */
	public ServerHistorian() {
		super();

	}

	/**
	 * Construct a new <code>ServerHistorian</code> using the given
	 * <code>Textbook</code> for output.
	 * 
	 * @param textbook
	 *        The textbook to output to.
	 */
	public ServerHistorian(Textbook textbook) {
		super(textbook);

	}

	/**
	 * Log an update that has happened to the server, for example, they have a
	 * new connection, or a turn has advanced.
	 * 
	 * @param source
	 *        The server that generated the message.
	 * @param message
	 *        The update message.
	 */
	public void logUpdateMessage(Server source, String message) {
		logMessage(source, message, UPDATE);
	}

	/**
	 * Log an error that has occurred that happened to the server.
	 * 
	 * @param source
	 *        The server that generated the error.
	 * @param message
	 *        The error message.
	 */
	public void logErrorMessage(Server source, String message) {
		logMessage(source, message, ERROR);
	}

	/**
	 * Log the information for a given turn. If this turn has already been
	 * logged, this info replaces it.
	 * 
	 * @param tFor
	 *        The turn that this is the information for. Note that this will be
	 *        the turn before the turn specified in the NOW and ORD commands.
	 * @param tInfo
	 *        The information on the turn we are logging.
	 */
	public void logTurn(Turn tFor, TurnInfo tInfo) {
		if (firstTurn == null || tFor == null) {
			firstTurn = tInfo;
		}

		turns.put(tFor, tInfo);

	}

	/**
	 * Gets the information for the specified turn.
	 * 
	 * @param turn
	 *        The turn we are getting information for.
	 * @return A TurnInfo containing information for the given turn.
	 */
	public TurnInfo getTurn(Turn turn) {
		return turns.get(turn);
	}

	/**
	 * Gets an iterator that can loop through all turns found so far, so long as
	 * all turns have been logged.
	 * 
	 * @return An iterator over all the turns.
	 */
	public Iterator<TurnInfo> turns(){
		return new Iterator<TurnInfo>() {

			/**
			 * The next turn information we will return.
			 */
			private Turn nextTurn = null;
			
			public boolean hasNext() {
				if(nextTurn != null)
					return turns.get(nextTurn) != null;
				
				return turns.size() > 0;
			}

			public TurnInfo next() {
				if(hasNext()) {
					if(nextTurn == null) {
						nextTurn = firstTurn.turn;
						return firstTurn;
					}
					return turns.get(nextTurn);
				}
				throw new NoSuchElementException();
			}

			public void remove() {
				throw new UnsupportedOperationException();
				
			}
			
		};
	}
}
